#ifndef __LS_FORMATTER_H__
#define __LS_FORMATTER_H__

#include "level.hpp"
#include "message.hpp"
#include <vector>
#include <sstream>

namespace log_system
{
    //格式化子项：日志等级子项，日期子项，文件名子项，行号子项，线程id子项，日志器名称子项，消息主体子项，制表符子项，换行子项，其他信息子项
    class FormatItem
    {
    public:
        using ptr = std::shared_ptr<FormatItem>;
        virtual void format(std::ostream& out, const LogMsg& msg) = 0;
    };
    

    class LevelFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out, const LogMsg& msg) override
        {
            out << LogLevel::toString(msg._logLevel);
        }
    };


    class DateFormatItem : public FormatItem
    {
    public:
        //年月日时分秒
        DateFormatItem(const std::string& fmt = "%Y/%m/%d %H:%M:%S"): _timeFmt(fmt){}

        void format(std::ostream& out, const LogMsg& msg) override
        {
            char buffer[50] = {0};
            strftime(buffer, sizeof(buffer), _timeFmt.c_str(), localtime(&msg._logTime));

            out << buffer;
        }
    private:
        std::string _timeFmt;   //日期子格式
    };

    class FileFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out, const LogMsg& msg) override
        {
            out << msg._file;
        }
    };

    class LineFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out, const LogMsg& msg) override
        {
            out << msg._line;
        }
    };

    class TIDFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out, const LogMsg& msg) override
        {
            out << msg._tid;
        }
    };

    class NameFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out, const LogMsg& msg) override
        {
            out << msg._logger;
        }
    };

    class MsgFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out, const LogMsg& msg) override
        {
            out << msg._payload;
        }
    };

    class TabFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out, const LogMsg& msg) override
        {
            out << '\t';
        }
    };
    
    class NewLineFormatItem : public FormatItem
    {
    public:
        void format(std::ostream& out, const LogMsg& msg) override
        {
            out << '\n';
        }
    };

    class OtherFormatItem : public FormatItem
    {
    public:
        OtherFormatItem(const std::string& str):_str(str){}
        void format(std::ostream& out, const LogMsg& msg) override
        {
            out << _str;
        }
    private:
        std::string _str;
    };

    /*
        %d 日期，包含子格式{%Y/%m/%d %H:%M:%S}
        %t 线程ID
        %c 日志器名称
        %f 源代码文件名
        %l 源代码行号
        %p 日志级别
        %T 制表符缩进
        %m 消息主体
        %n 换行符
    */
    class Formatter
    {
    public:
        using ptr = std::shared_ptr<Formatter>;
        Formatter(const std::string& pattern = "[%d{%Y/%m/%d %H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n"):_pattern(pattern)
        {
            if(!parse())
                abort();
        }

        void format(std::ostream& out, const LogMsg& msg)
        {
            for(auto& item : _items)
            {
                item->format(out, msg);
            }
        }

        std::string format(const LogMsg& msg)
        {
            std::stringstream ss;
            format(ss, msg);
            return ss.str();
        }


    private:
        bool parse()
        {
            std::vector<std::pair<std::string, std::string>> fmt_order;
            size_t pos = 0;
            std::string key, val;
            while(pos < _pattern.size())
            {
                // 1.对格式化规则字符串进行解析

                //解析Other字符串
                while(pos < _pattern.size())
                {
                    size_t mark = _pattern.find_first_of("%", pos);
                    if(mark == std::string::npos)
                    {
                        val += _pattern.substr(pos, std::string::npos);
                        pos = _pattern.size();
                        break;      //跳出循环，后续来构建Other子项的kv对
                    }
                    else
                    {
                        val += _pattern.substr(pos, mark - pos);
                        //pos指向%后一位
                        pos = mark + 1;
                        if(pos < _pattern.size())
                        {
                            if(_pattern[pos] == '%')
                            {
                                val += '%';
                                pos += 1;
                            }
                            else
                            {
                                // 若不是%%，认为是格式化字符，跳出该循环，后续来构建Other子项的kv对
                                break;
                            }
                        }
                        else
                        {
                            std::cerr << "%后无格式化字符！" << std::endl;
                            return false;
                        }
                    } // mark != std::string::npos
                } // while
                // 达到末尾或遇到格式化字符串，认为解析完了一个Other字符串


                // 构建other子项的kv对。
                if(!val.empty())
                {
                    fmt_order.push_back(std::make_pair("", val));
                    val.clear();
                }
                

                //解析一段格式化标签
                if(pos < _pattern.size())
                {
                    key = _pattern[pos];

                    pos += 1;
                    if(pos < _pattern.size() && _pattern[pos] == '{')
                    {
                        size_t subMark = _pattern.find_first_of("}", pos);
                        if(subMark == std::string::npos)
                        {
                            std::cerr << "子格式{}匹配失败" << std::endl;
                            return false;
                        }
                        else
                        {
                            // 找到了}，pos+1一定不越界。
                            //将{}内（不含{}）的格式化字符串作为子格式化标签
                            val += _pattern.substr(pos + 1, subMark - 1 - pos);
                            pos = subMark + 1;
                        }
                    }
                }

                //一段格式化标签解析完成
                if(!key.empty())
                {
                    fmt_order.push_back(std::make_pair(key, val));
                    key.clear();
                    val.clear();
                }

            }
            // 2.根据解析得到的数据初始化格式化子项数组
            for(auto& it : fmt_order)
            {
                _items.push_back(createItem(it.first, it.second));
            }
            return true;
        }
    
        FormatItem::ptr createItem(const std::string &key, const std::string& val)
        {
            if(key.empty()) return std::make_shared<OtherFormatItem>(val);
            else if(key == "d") return std::make_shared<DateFormatItem>(val);
            else if(key == "t") return std::make_shared<TIDFormatItem>();
            else if(key == "c") return std::make_shared<NameFormatItem>();
            else if(key == "f") return std::make_shared<FileFormatItem>();
            else if(key == "l") return std::make_shared<LineFormatItem>();
            else if(key == "p") return std::make_shared<LevelFormatItem>();
            else if(key == "T") return std::make_shared<TabFormatItem>();
            else if(key == "m") return std::make_shared<MsgFormatItem>();
            else if(key == "n") return std::make_shared<NewLineFormatItem>();
            else { std::cerr << "无效的格式化字符:%" << key << std::endl; abort(); }
        }


    private:
        std::string _pattern;   //格式化规则字符串
        std::vector<FormatItem::ptr> _items;    //格式化子项数组
    };


}


#endif